import * as fs from 'fs';
import * as path from 'path';
import config from '../config';
import { compareVersion, copyDirectory, createDirectory, deleteDirectory, eachFiles, executeCmd, getCliConfigData, getProjectVersion, isDirectoryEmpty, searchFiles, trimPath } from '../utils';

export default async function (projectPath: string) {
    projectPath = trimPath(projectPath);
    console.log('项目路径: ' + projectPath);
    if (!projectPath || isDirectoryEmpty(projectPath)) return console.log('请输入有效文件夹路径');

    // 获取cliconfig数据
    const projectCliData = getCliConfigData(projectPath);
    if (!projectCliData) return console.log('未在项目根目录下找到cliconfig.json');

    // 获取引擎类型
    if (!config.types[projectCliData.type]) {
        return console.log(`未知的引擎类型: ${projectCliData.type}`);
    }

    // 模版临时目录
    const templatePath = path.join(__dirname, 'template');
    deleteDirectory(templatePath);

    // 下载源码
    if (projectCliData.type === config.types.Creator3D) {
        const gitAddress = config.gits[config.types.Creator3D];
        console.log('拉取中: git clone ' + gitAddress);
        const code = await executeCmd('git', ['clone', '--depth=1', gitAddress, `"${templatePath}"`]);
        if (code != 0) {
            console.error('拉取失败');
            return;
        }
    } else {
        const gitAddress = config.gits[config.types.Creator];
        console.log('拉取中: git clone ' + gitAddress);
        const code = await executeCmd('git', ['clone', '--depth=1', gitAddress, `"${templatePath}"`]);
        if (code != 0) {
            console.error('拉取失败');
            return;
        }
    }

    // 框架cliconfig数据
    const frameCliData = getCliConfigData(templatePath);

    if (!frameCliData) {
        console.log('未找到cliconfig.json: ' + templatePath);
        return
    }
    // 相同不需要更新
    // if (frameCliData && frameCliData.version === projectCliData.version) {
    //     return console.log('已是最新版, 无需更新');
    // }

    // 更新文件夹
    function upgradeFolderForce(...paths: string[]) {
        deleteDirectory(path.join(projectPath, ...paths));
        copyDirectory(path.join(templatePath, ...paths), path.join(projectPath, ...paths));
    }

    // 更新文件
    function upgradeFileForce(...paths: string[]) {
        if (fs.existsSync(path.join(projectPath, ...paths)))
            fs.unlinkSync(path.join(projectPath, ...paths));
        if (fs.existsSync(path.join(templatePath, ...paths)))
            fs.copyFileSync(path.join(templatePath, ...paths), path.join(projectPath, ...paths));
    }

    function upgradeJsonSoft(...paths: string[]) {
        const handle = (data: object, original: object) => {
            for (const key in data) {
                if (!Object.prototype.hasOwnProperty.call(data, key)) {
                    continue;
                }
                if (data[key] && typeof data[key] === 'object' && original[key] && typeof original[key] === 'object') {
                    handle(data[key], original[key]);
                } else if (!original[key] || original[key] != data[key]) {
                    if (key === 'version' && typeof data[key] === 'string' && typeof original[key] === 'string') {
                        // version字段特殊处理，取大版本
                        if (compareVersion(data[key], '>', original[key])) {
                            original[key] = data[key];
                        }
                    } else {
                        original[key] = data[key];
                    }
                }
            }
            return original;
        };

        const projectFilePath = path.join(projectPath, ...paths);
        const templateFilePath = path.join(templatePath, ...paths);

        if (fs.existsSync(projectFilePath)) {
            if (fs.existsSync(templateFilePath)) {
                const out = handle(JSON.parse(fs.readFileSync(templateFilePath, 'utf-8')), JSON.parse(fs.readFileSync(projectFilePath, 'utf-8')));
                fs.writeFileSync(projectFilePath, JSON.stringify(out, null, '  '), 'utf-8');
            } else {
                fs.unlinkSync(projectFilePath);
            }
        } else if (fs.existsSync(templateFilePath)) {
            fs.copyFileSync(templateFilePath, projectFilePath);
        }
    }

    if (frameCliData.type === config.types.Creator) {
        // 更新插件
        eachFiles(path.join(templatePath, 'packages'), function (item_path, isDirectory) {
            if (!isDirectory) return;
            deleteDirectory(path.join(projectPath, 'packages', path.basename(item_path)));
            copyDirectory(item_path, path.join(projectPath, 'packages', path.basename(item_path)));
        });

        // 更新app
        deleteDirectory(path.join(projectPath, 'assets/app'));
        copyDirectory(path.join(templatePath, 'assets/app'), path.join(projectPath, 'assets/app'));
    } else {
        const pkgDir = path.join(projectPath, 'extensions', 'pkg');
        if (fs.existsSync(pkgDir)) {
            // 如果是把package存放在assets中的情况，移动到node_modules文件夹下
            if (fs.existsSync(path.join(pkgDir, 'assets'))) {
                fs.renameSync(path.join(pkgDir, 'assets'), path.join(pkgDir, 'node_modules'));
            } else {
                // 如果是老版本升级上来的是没有node_modules文件夹的，需要将package/node_modules拷贝到node_modules文件夹下
                if (!fs.existsSync(path.join(pkgDir, 'node_modules'))) {
                    createDirectory(path.join(pkgDir, 'node_modules'));
                    copyDirectory(path.join(pkgDir, 'package', 'node_modules'), path.join(pkgDir, 'node_modules'));
                }
                // 3.3.10开始 移除pkg/package
                if (fs.existsSync(path.join(pkgDir, 'package'))) {
                    if (fs.existsSync(path.join(pkgDir, 'package', 'package.json'))) {
                        const _json = fs.readFileSync(path.join(pkgDir, 'package', 'package.json'), 'utf-8');
                        const _data = JSON.parse(_json);

                        const json = fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf-8');
                        const data = JSON.parse(json);
                        data.dependencies = _data.dependencies;
                        fs.writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify(data, null, '\t'), 'utf-8');
                    }
                    deleteDirectory(path.join(pkgDir, 'package'));
                }
            }
        }

        // 更新插件
        eachFiles(path.join(templatePath, 'extensions'), function (extensionPath, isDirectory) {
            if (!isDirectory) return;
            const extensionName = path.basename(extensionPath);
            if (extensionName === 'pkg') {
                upgradeJsonSoft('extensions', 'pkg', 'package.json');
                upgradeFileForce('extensions', 'pkg', 'index.js');
                upgradeFileForce('extensions', 'pkg', 'README.md');
            } else {
                upgradeFolderForce('extensions', extensionName);
            }
        });

        // 如果是从3.8.0以下更新到3.8.0及以上，更新builder.json文件
        const projectCocosVersion = getProjectVersion(projectPath);
        const templateCocosVersion = getProjectVersion(templatePath);
        if (compareVersion(projectCocosVersion, '<', '3.8.0') && compareVersion(templateCocosVersion, '>=', '3.8.0')) {
            upgradeFileForce('settings/v2/packages/builder.json');
            upgradeFileForce('settings/v2/packages/scene.json');

            // 更新项目内所有bundle配置
            searchFiles(path.join(projectPath, 'assets'), (filePath, isDirectory) => {
                if (isDirectory) return;
                if (!filePath.endsWith('.meta')) return;

                const metaStr = fs.readFileSync(filePath, 'utf-8');
                if (metaStr.indexOf('isBundle') === -1) return;

                const metaObj = JSON.parse(metaStr);
                if (!metaObj?.userData?.isBundle) return;

                delete metaObj.userData.isRemoteBundle;
                delete metaObj.userData.compressionType;

                if (filePath.indexOf('app-builtin') >= 0) {
                    // app-builtin
                    metaObj.userData.bundleConfigID = 'auto_398Ij6Mc1B2Y7sW3e6BgFC';
                } else if (filePath.indexOf('app-bundle') >= 0) {
                    if (filePath.endsWith('native.meta')) {
                        // app-native
                        metaObj.userData.bundleConfigID = 'auto_f7NI9WxFVIO6e8LbJGF72k';
                    } else {
                        // app-res
                        metaObj.userData.bundleConfigID = 'auto_11aBEBWDxI/6ryvKvFthEo';
                    }
                } else {
                    // default
                    metaObj.userData.bundleConfigID = 'default';
                }

                fs.writeFileSync(filePath, JSON.stringify(metaObj, null, '  '), 'utf-8');
            });
        }

        // 如果项目中没有web模版，拷贝过来
        if (!fs.existsSync(path.join(projectPath, 'web-template')) && fs.existsSync(path.join(templatePath, 'web-template'))) {
            copyDirectory(path.join(templatePath, 'web-template'), path.join(projectPath, 'web-template'));
        }
    }

    // 更新cliconfig.json
    upgradeFileForce('cliconfig.json');

    // 更新readme.md
    upgradeFileForce('readme.md');

    // 更新eslint配置
    upgradeFileForce('.eslintrc.js');
    upgradeFileForce('.eslintignore');

    // 更新git配置
    upgradeFileForce('.gitignore');

    // 更新package.json
    upgradeJsonSoft('package.json');

    // 更新builder.json
    upgradeJsonSoft('settings/v2/packages/builder.json');

    console.log(`更新成功，版本号: ${projectCliData.version} => ${frameCliData.version}`);
    console.log('查看更新日志: https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017425&doc_id=6236543');
    deleteDirectory(templatePath);
}